package com.warm.service.impl;

import com.warm.exception.SellException;
import com.warm.service.RedisLock;
import com.warm.service.SecKillService;
import com.warm.utils.KeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by liangchuang on 2018/10/5.
 * Description:
 */
@Service
public class SecKillServiceImpl implements SecKillService {

    @Autowired
    private RedisLock redisLock;

    private static final int TIMEOUT = 10 * 1000;

    //模拟抢购,国庆活动 10000份
    static Map<String, Integer> products;
    static Map<String, Integer> stock;
    static Map<String, String> orders;
    {
        //模拟多个表，商品信息表,库存表,秒杀成功顶单表
        products = new HashMap<>();
        stock = new HashMap<>();
        orders = new HashMap<>();
        products.put("123456", 10000);
        stock.put("123456", 10000);
    }

    private String queryMap(String productId){
        return "国庆活动，胡辣汤特价,限量份"
                + products.get(productId)
                + " 还剩: " + stock.get(productId) + " 份"
                + " 该商品成功下单用户数目: "
                + orders.size() + " 人" ;
    }

    @Override
    public String querySecKillProductInfo(String productId) {
        return this.queryMap(productId);
    }

    /**
     * 处理多线程问题:1.使用synchronized
     *                    每次只执行一个线程,速度慢
     *                    无法做到细粒度控制
     *                    只适合单点的情况
     *              2.使用redis分布式锁
     *                   支持分布式
     *                   可以更细粒度的控制
     *                   多台机器上多个进程对一个数据进行操作的互斥
     */
    @Override
    public void orderProductMockDiffUser(String productId) {

        //加锁
        long time = System.currentTimeMillis() + TIMEOUT;
        if(!redisLock.lock(productId, String.valueOf(time))){
            throw new SellException(101, "哎呦喂, 人太多了,换个姿势再试试");
        }

        //1.查询该商品库存,为0则活动结束
        int stockNum = stock.get(productId);
        if(stockNum == 0){
            throw new SellException(100, "活动结束");
        }else{
            //2.下单 模拟不同的用户的openid
            orders.put(KeyUtil.genUniqueKey(), productId);
            //3.减库存
            stockNum = stockNum - 1;
            try{
                Thread.sleep(100);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            stock.put(productId, stockNum);
        }
        //解锁
        redisLock.unlock(productId, String.valueOf(time));
    }
}
